package me.evis.mobile.sms2cal;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import me.evis.mobile.sms2cal.model.CalAlarm;
import me.evis.mobile.sms2cal.model.CalEvent;
import me.evis.mobile.sms2cal.model.SmsData;
import me.evis.mobile.sms2cal.parser.FlightReminderParser;
import me.evis.mobile.sms2cal.parser.SmsParser;
import me.evis.mobile.sms2cal.provider.CalEventContentProvider;
import me.evis.mobile.sms2cal.provider.ParseLogContentProvider;
import me.evis.mobile.sms2cal.provider.ParsedEventContentProvider;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.preference.PreferenceManager;
import android.util.Log;

public class SmsBatchParser {
    /** Tag string for debug logs */
    private static final String TAG = "me.evis.mobile.sms2cal.SmsBatchParser";
    
    private static final int DEFAULT_ALARM_TIME = 10;
    
    private Context context;
    
    public SmsBatchParser(Context context) {
        this.context = context;
    }
    
    /**
     * @deprecated only for test.
     */
    @Deprecated
    public void parseSmsData(List<SmsData> smsDatas) {
        List<SmsParser> parsers = new ArrayList<SmsParser>();
        parsers.add(new FlightReminderParser());
        parseSmsData(smsDatas, parsers);
    }
    
    public void parseSmsData(List<SmsData> smsDatas, List<SmsParser> parsers) {
        List<CalEvent> results = new ArrayList<CalEvent>();
        Map<SmsData, Integer> smsToParseLogId = new HashMap<SmsData, Integer>();
        
        // Get parser mode from Preference.
        SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        String aggressive = context.getResources().getStringArray(R.array.pref_parser_mode_values)[0];
        boolean isAutoAddToCal = 
                aggressive.equals(preferences.getString(context.getString(R.string.prefkey_parser_mode), aggressive));
        
        for (SmsData sms : smsDatas) {
            // TODO handle blacklist
            
            for (SmsParser parser : parsers) {
                if (parser.parse(sms, results)) {
                    int logId = insertParseLog(sms);
                    smsToParseLogId.put(sms, logId);
                    break;
                }
            }
        }
        
        // handle parse result.
        for (CalEvent event : results) {
            insertCalEvent(smsToParseLogId.get(event.sourceSms), event);
            // Add to calendar if in aggressive mode.
            if (isAutoAddToCal) {
                CalendarUtil.addToCalendar(context, event);
            }
        }
    }
    
    private int insertParseLog(SmsData sms) {
        ContentValues values = new ContentValues();
        
        values.put(ParseLogContentProvider.PARSE_DATE, System.currentTimeMillis());
        putNotNull(values, ParseLogContentProvider.RECEIVE_DATE, sms.receiveOn);
        values.put(ParseLogContentProvider.SMS_BODY, sms.messageBody);
        values.put(ParseLogContentProvider.SMS_FROM, sms.fromDisplayName);
        values.put(ParseLogContentProvider.READ, false);
        
        Uri inserted = context.getContentResolver().insert(ParseLogContentProvider.CONTENT_URI, values);
        Log.d(TAG, "Insert a new ParseLog with URI: " + inserted);
        return Integer.parseInt(inserted.getLastPathSegment()); 
    }
    
    private void insertCalEvent(int parseLogId, CalEvent event) {
        ContentValues values = new ContentValues();
        
        values.put(CalEventContentProvider.CATEGORIES, event.categories);
        values.put(CalEventContentProvider.CLASSIFICATION, event.classification);
        values.put(CalEventContentProvider.DESCRIPTION, event.description);
        putNotNull(values, CalEventContentProvider.DTEND, event.dtEnd);
        putNotNull(values, CalEventContentProvider.DTSTAMP, event.dtStamp);
        putNotNull(values, CalEventContentProvider.DTSTART, event.dtStart);
        values.put(CalEventContentProvider.LOCATION, event.location);
        values.put(CalEventContentProvider.SUMMARY, event.summary);
        values.put(CalEventContentProvider.PARSELOG_ID, parseLogId);
        
        Uri inserted = context.getContentResolver().insert(CalEventContentProvider.CONTENT_URI, values);
        int calEventId = Integer.parseInt(inserted.getLastPathSegment());
        insertCalAlarm(calEventId, event);
        Log.d(TAG, "Insert a new CalEvent whose VEVENT is: " + event.toVEVENT());
        
        showNotification(calEventId, event);
    }
    
    private void insertCalAlarm(int calEventId, CalEvent calEvent) {
        final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
        final boolean alarmEnabled = 
                preferences.getBoolean(context.getString(R.string.prefkey_event_alarm_enabled), true);
        final int alarmTime = Integer.parseInt(
                preferences.getString(context.getString(R.string.prefkey_event_alarm_time), 
                        String.valueOf(DEFAULT_ALARM_TIME)));
        
        if (alarmEnabled) {
            CalAlarm calAlarm = new CalAlarm();
            calAlarm.description = calEvent.description;
            calAlarm.triggerMinutes = alarmTime;
            calEvent.addCalAlarm(calAlarm);
        }
    }
    
    private void showNotification(int calEventId, CalEvent calEvent) {
        NotificationManager notificationManager = 
            (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
        Notification notification = new Notification(R.drawable.ic_notify_info, 
                context.getText(R.string.notify_new_parsed_event_title), 
                System.currentTimeMillis());
        
        Intent intent = new Intent(Intent.ACTION_VIEW, 
                ContentUris.withAppendedId(ParsedEventContentProvider.CONTENT_URI, calEventId));
        PendingIntent contentIntent = PendingIntent.getActivity(context, 0, intent, 0);
        notification.setLatestEventInfo(context, 
                context.getText(R.string.notify_new_parsed_event_title), 
                context.getText(R.string.notify_new_parsed_event_text) + calEvent.summary, 
                contentIntent);
        notification.flags = Notification.FLAG_AUTO_CANCEL;
        
        notificationManager.notify(R.string.app_notification_id, notification);
    }
    
    /**
     * Only put into values when value is not null.
     */
    private void putNotNull(ContentValues values, String key, Date value) {
        if (value != null) {
            values.put(key, value.getTime());
        }
    }
}
